package com.lancoo.ccas53.arrangecourse;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.lancoo.ccas53.arrangecourse.AlgDataSource.common.SchedulingProcessData;
import com.lancoo.ccas53.arrangecourse.clashesprocess.ClashesProcess;
import com.lancoo.ccas53.arrangecourse.common.BinaryUtil;
import com.lancoo.ccas53.arrangecourse.common.ClassHourUtil;
import com.lancoo.ccas53.arrangecourse.coursescheduling.SchoolScheduling;
import com.lancoo.ccas53.arrangecourse.dataprocess.ClassHourScheduleConvert;
import com.lancoo.ccas53.arrangecourse.dataprocess.GenerateTimeslotRoom;
import com.lancoo.ccas53.arrangecourse.dataprocess.TeacherAndCourseProhibitProcess;
import com.lancoo.ccas53.arrangecourse.entities.BaseRule;
import com.lancoo.ccas53.arrangecourse.entities.ClassHour;
import com.lancoo.ccas53.arrangecourse.entities.CourseUnit;
import com.lancoo.ccas53.arrangecourse.entities.TimeslotRoom;
import com.lancoo.ccas53.entity.*;
import com.lancoo.ccas53.exception.BizException;
import com.lancoo.ccas53.mapper.ScheduleMapper;
import com.lancoo.ccas53.mapper.TeachingClassMapper;
import com.lancoo.ccas53.mapper.TeachingClassStudentMapper;
import com.lancoo.ccas53.mapper.TeachingClassWeekMapper;
import com.lancoo.ccas53.pojo.constant.ScheduleState;
import com.lancoo.ccas53.pojo.dto.*;
import com.lancoo.ccas53.pojo.vo.CollegeRoomVo;
import com.lancoo.ccas53.pojo.vo.WeekDateVo;
import com.lancoo.ccas53.service.RuleUsableService;
import com.lancoo.ccas53.service.ScheduleSelectService;
import com.lancoo.ccas53.service.TaskInfoService;
import com.lancoo.ccas53.service.TeachingClassWeekService;
import com.lancoo.ccas53.util.BatchInsert;
import com.lancoo.ccas53.util.WeekUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * @Description 课程安排服务
 * @Author Fortysun
 * @Date 2023-03-30 10:44
 */
@Slf4j
@Component
public class ArrangeCourseServiceImpl implements ArrangeCourseService {

    //排课数据源
    @Resource
    ArrangeCourseDataSource arrangeCourseDataSource;

    //计算冲突
    @Resource
    ClashesProcess clashesProcess;
    @Resource
    TaskInfoService taskInfoService;
    @Resource
    ScheduleMapper scheduleMapper;
    @Resource
    TeachingClassStudentMapper teachingClassStudentMapper;
    @Resource
    TeachingClassWeekService teachingClassWeekService;
    @Resource
    TeachingClassWeekMapper teachingClassWeekMapper;
    @Resource
    ScheduleSelectService scheduleSelectService;
    @Resource
    TeachingClassMapper teachingClassMapper;
    @Resource
    RuleUsableService ruleUsableService;

    ClassHourScheduleConvert convertor = null;

    public ArrangeCourseServiceImpl() {
        //初始化，类型转换的类
        convertor = new ClassHourScheduleConvert();
    }

    /**
     * 算法排课  有四种排课方式：<br>
     * <ol>
     * <li>院系管理员排课  collegeId传对应院系id majorProp传2</li>
     * <li>教务管理员排课 collegeId传空字符串 majorProp传1</li>
     * <li>自动分配教室 collegeId传null majorProp传null，collegeId传null获取禁排规则时会返回空列表</li>
     * <li>仅教务管理员排课 collegeId传空字符串 majorProp传null，collegeId传空字符串获取管理员设置的一套禁排规则即可</li>
     * </ol>
     *
     * @param taskId    排课计划id
     * @param collegeId 院系id，教务管理员登录传空字符串,确认排课结果，自动调整传null
     * @param majorProp 课程类型，1：公共课， 2：专业课
     */
    @Override
    public void algService(Integer taskId, String collegeId, Integer majorProp) {
        //获取学期排课选课计划信息
        TaskInfo taskInfo = arrangeCourseDataSource.getTaskInfo(taskId);
        if (taskInfo != null) {
            log.info("#ArrangeCourseServiceImpl.algService#--开始自动排课，taskId为{}的计划信息获取成功", taskId);
            //0各校区独立排课 1全校统一排课
            Integer crossCampusOption = 1;
            //学校id
            String schoolId = taskInfo.getSchoolId();
            //学期id
            String termId = taskInfo.getTerm();

            //开启跨校区排课，全校所有的课程，将安排到所有校区的教室
            ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> retMap = startScheduling(schoolId,
                    termId, taskId, crossCampusOption, collegeId, majorProp);

            //将排课的数据，进行冲突检测、教学班排课状态标记，最后同步写入数据库；
            syncData2DB(taskId, retMap, collegeId, majorProp);
            //清空任务数据
            SchedulingProcessData.clearSchedulingProcessData(taskId);
            log.info("#ArrangeCourseServiceImpl.algService#--自动排课已完成");
        }
    }

    /**
     * 获取排课规则，自定排课的时候，进行处理
     *
     * @param taskId            计划id
     * @param crossCampusOption 跨校区排课规则
     * @param collegeId         院系id，教务管理员登录传空字符串,确认排课结果，自动调整传null
     * @return
     */
    private BaseRule getScheduleRule(String schoolId, String termId, Integer taskId, Integer crossCampusOption, String collegeId) {
        List<RuleUsable> ruleList = arrangeCourseDataSource.getBaseRuleList(schoolId, termId, taskId, collegeId);
        if (CollUtil.isEmpty(ruleList)) {
            throw new BizException("管理员未设置排课规则，请管理员先设置排课规则");
        }
        if (ruleList != null && !ruleList.isEmpty()) {
            crossCampusOption = 1;
            //跨校区时间，a不启用，b半天 c一天
            String crossCampusRule = "b";
            //课程分布
            String courseDistribution = "a";
            //教师分布
            String teacherDistribution = "a";
            //教师每天最大的上课节次
            Integer maxSection = Integer.MAX_VALUE;
            Integer maxCourseSection = Integer.MAX_VALUE;
            //环节排课，a无需求，b环节所在周次不怕苦
            String segmentArrange = "a";


            //教务处排课范围
            String courseRange = "0000";

            //获取用户设置的教师、课程分布情况
            for (RuleUsable rule : ruleList) {
                //规则类型
                Integer code = rule.getCode();
                //用户选项
                Integer option = rule.getOptionType();
                switch (code) {
                    case 1:
                        if (option == 1 || option == 0) { // 不跨
                            crossCampusOption = 0;
                        } else {
                            crossCampusOption = 1;
                            if (option == 2) {
                                //半天
                                crossCampusRule = "b";
                            } else {
                                //一天
                                crossCampusRule = "c";
                            }

                        }

                        break;
                    case 2:
                        if (option == 0) {
                            teacherDistribution = "a";
                        } else if (option == 1) {
                            teacherDistribution = "b";
                        } else {
                            teacherDistribution = "c";
                        }
                        break;
                    case 3:
                        if (option == 0) {
                            courseDistribution = "a";
                        } else if (option == 1) {
                            courseDistribution = "b";
                        } else {
                            courseDistribution = "c";
                        }
                        break;
                    case 4:
                        if (option == 0) {
                            segmentArrange = "a";
                        } else if (option == 1) {
                            segmentArrange = "b";
                        }
                        break;
                    case 5:
                        if (option != 0) {
                            maxSection = option;
                        }
                        break;
                    case 6:
                        if (option != 0) {
                            courseRange = String.format("%04d", option);
                        }
                        break;
                    case 7:
                        if (option != 0) {
                            maxCourseSection = option;
                        }
                        break;
                }
            }

            log.info("#ArrangeCourseServiceImpl.getScheduleRule#--跨校区规则标识为：" + crossCampusOption
                    + "基础规则设置的课程范围为：" + courseDistribution
                    + ", 教师范围为：" + teacherDistribution
                    + "，教师单日最大上课节次为：" + maxSection);
            return new BaseRule(crossCampusOption, crossCampusRule, courseDistribution,
                    teacherDistribution, maxSection, maxCourseSection, segmentArrange, courseRange);
        }
        log.error("#ArrangeCourseServiceImpl.getScheduleRule#--基础规则信息获取失败");
        return null;
    }

    /**
     * 获取指定院系的排课场地信息列表
     *
     * @param roomList          全校场地信息列表
     * @param collegeRoomVOList 院系指定的场地信息列表
     * @return
     */
    private List<ArrangeRoomDto> getScheduleRoomList(List<ArrangeRoomDto> roomList,
                                                     List<CollegeRoomVo> collegeRoomVOList) {
        //定义返回的教室信息列表
        List<ArrangeRoomDto> retRoomList = null;
        if (collegeRoomVOList != null && !collegeRoomVOList.isEmpty()) {
            //初始化列表
            retRoomList = new ArrayList<>();
            //如果是教务管理员排公共课，会返回所有院系的场地信息过来
            if (collegeRoomVOList.size() > 1) {
                retRoomList = roomList;
            } else {//院系设置了场地范围
                //获取当前院系的场地范围，如果是指定的院系，那么列表只有一条数据，所以只取第一条数据即可
                List<CollegeRoom> collegeRoomList = collegeRoomVOList.get(0).getCollegeRooms();
                if (collegeRoomList != null && !collegeRoomList.isEmpty()) {
                    for (CollegeRoom collegeRoom : collegeRoomList) {
                        for (ArrangeRoomDto roomInfo : roomList) {
                            //将属于这个院系的排课场地的教室信息，加入列表进行返回
                            if (collegeRoom.getRoomId().equals(roomInfo.getRoomId())) {
                                retRoomList.add(roomInfo);
                            }
                        }
                    }
                } else {
                    //TODO 存在两种情况，院系没有设置场地信息，返回全部的场地信息
                    retRoomList = roomList;
                }
            }
        } else {//如果为空，返回全部的场地信息
            retRoomList = roomList;
        }

        return retRoomList;
    }

    /**
     * 开启排课
     *
     * @param schoolId          学校id
     * @param termId            学期id
     * @param taskId            学期排课计划id
     * @param crossCampusOption 跨校区排课标识，1：跨校区排课，0：各校区独立排课
     * @param collegeId         院系id，教务管理员登录传空字符串,确认排课结果，自动调整传null
     * @param majorProp         课程类型，1：公共课， 2：专业课
     */
    private ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> startScheduling(String schoolId,
                                                                                       String termId,
                                                                                       Integer taskId,
                                                                                       Integer crossCampusOption,
                                                                                       String collegeId,
                                                                                       Integer majorProp) {
        //获取排课教学班数据；
        List<ArrangeTeachingClassDto> teachingClassList = arrangeCourseDataSource.getTeachingClassList(taskId, null, collegeId, majorProp);
        log.info("#ArrangeCourseServiceImpl.startScheduling#--获取到{}个排课教学班", teachingClassList.size());
        if (teachingClassList != null && !teachingClassList.isEmpty()) {
            //获取学期的周次信息
            WeekDateVo weekInfo = arrangeCourseDataSource.getTermWeeks(taskId);
            //获取学期总周数，默认16周
            Long weekNum = 16L;
            if (weekInfo != null) {
                //获取学期总周数
                weekNum = weekInfo.getWeekCount();
                log.info("#ArrangeCourseServiceImpl.startScheduling#--学期总周数信息获取成功，当前学期共{}周", weekNum);
            }

            //获取基础排课规则信息；
            BaseRule baseRule = getScheduleRule(schoolId, termId, taskId, crossCampusOption, collegeId);
            crossCampusOption = baseRule.getCrossCampusOption();
            log.info("#ArrangeCourseServiceImpl.startScheduling#--基础规则信息获取完成");
            //获取排课教室数据
            List<ArrangeRoomDto> roomList = arrangeCourseDataSource.getRoomList(taskId, schoolId, termId, null);
            log.info("#ArrangeCourseServiceImpl.startScheduling#--排课教室信息获取完成，共{}间教室", (roomList != null ? roomList.size() : 0));

            updateRoomType(teachingClassList,roomList);

            String rule = baseRule.getCourseRange();
            //已经过滤学院
            List<ArrangeTeachingClassDto> collegeTeachingClassList = teachingClassList.stream().filter(o ->
                    (rule.charAt(0) == '0' && o.getMajorProp() == 2 && o.getStudyNature() == 1)
                            || (rule.charAt(1) == '0' && o.getMajorProp() == 2 && o.getStudyNature() == 2)
                            || (rule.charAt(2) == '0' && o.getMajorProp() == 1 && o.getStudyNature() == 1)
                            || (rule.charAt(3) == '0' && o.getMajorProp() == 1 && o.getStudyNature() == 2)
            ).collect(Collectors.toList());

            List<ArrangeTeachingClassDto> adminTeachingClassList = teachingClassList.stream().filter(o ->
                    (rule.charAt(0) == '1' && o.getMajorProp() == 2 && o.getStudyNature() == 1)
                            || (rule.charAt(1) == '1' && o.getMajorProp() == 2 && o.getStudyNature() == 2)
                            || (rule.charAt(2) == '1' && o.getMajorProp() == 1 && o.getStudyNature() == 1)
                            || (rule.charAt(3) == '1' && o.getMajorProp() == 1 && o.getStudyNature() == 2)
            ).collect(Collectors.toList());


            if (StrUtil.isNotEmpty(collegeId)) {
                //获取排课院系，指定的场地范围
                List<Long> collegeRoomList = arrangeCourseDataSource.getCollegeRoomList(taskId, collegeId);
                //获取院系指定的场地列表信息
//                roomList = getScheduleRoomList(roomList, collegeRoomList);
                roomList = roomList.stream().filter(o -> collegeRoomList.contains(o.getRoomId())).collect(Collectors.toList());
                teachingClassList = collegeTeachingClassList;
            } else {
                teachingClassList = adminTeachingClassList;
            }

            //拆班的 添加完整数据
            List<String> subIds = new ArrayList<>();
            teachingClassList.forEach(o -> {
                if (StrUtil.isNotEmpty(o.getUniqueShiftSign())) {
                    subIds.add(o.getUniqueShiftSign());
                }
            });
            List<ArrangeTeachingClassDto> subTeachingClassList = arrangeCourseDataSource.getSubTeachingClassList(subIds);
            List<Long> exist = teachingClassList.stream().map(ArrangeTeachingClassDto::getTeachingClassId).distinct().collect(Collectors.toList());
            for (ArrangeTeachingClassDto o : subTeachingClassList) {
                if (!exist.contains(o.getTeachingClassId())) {
                    teachingClassList.add(o);
                }
            }


            log.info("#ArrangeCourseServiceImpl.startScheduling#--排课教室信息获取完成，共{}间教室", (roomList != null ? roomList.size() : 0));
            //获取排课课时数据；
            List<ArrangePeriod> timeslotList = arrangeCourseDataSource.getTimeslotList(taskId, schoolId, termId, null);
            log.info("#ArrangeCourseServiceImpl.startScheduling#--排课课时信息获取完成，共{}个课时", (timeslotList != null ? timeslotList.size() : 0));
            //获取教室禁排数据
            List<ArrangeRoomRuleDto> roomProhibitList = arrangeCourseDataSource.getRoomRuleList(taskId, schoolId, termId, null, null);
            log.info("#ArrangeCourseServiceImpl.startScheduling#--教室禁排规则信息获取完成，共{}条规则", (roomProhibitList != null ? roomProhibitList.size() : 0));
            //获取教师排课规则
            List<ArrangeTeacherRuleDto> teacherRuleList = arrangeCourseDataSource.getTeacherRuleList(taskId, schoolId, termId, null);
            log.info("#ArrangeCourseServiceImpl.startScheduling#--教师规则信息获取完成，共{}条规则", (teacherRuleList != null ? teacherRuleList.size() : 0));
            //获取课程禁排数据
            List<ArrangeCourseRuleDto> courseRuleList = arrangeCourseDataSource.getCourseRuleList(taskId, null);
            log.info("#ArrangeCourseServiceImpl.startScheduling#--课程规则信息获取完成，共{}条规则", (courseRuleList != null ? courseRuleList.size() : 0));
            //课程限制规则
            List<Course> courseLimitRuleList = arrangeCourseDataSource.getCourseLimitRuleList(taskId);
            log.info("#ArrangeCourseServiceImpl.startScheduling#--课程限制规则信息获取完成，共{}条规则", (courseLimitRuleList != null ? courseLimitRuleList.size() : 0));

            //取指定学校，已结束排课计划以及当前排课计划已锁定的课表信息
            List<ArrangeScheduleDto> scheduleList = arrangeCourseDataSource.getLockedScheduleList(
                    taskId, null, 2, majorProp, collegeId, StrUtil.isNotEmpty(collegeId) ? adminTeachingClassList : collegeTeachingClassList);
            log.info("#ArrangeCourseServiceImpl.startScheduling#--同学期其他计划以及本计划锁定的课表信息获取完成，共{}条记录",
                    (scheduleList != null ? scheduleList.size() : 0));
            //将获取的锁定的课表，转换成ClassHour排课课时对象
            CopyOnWriteArrayList<ClassHour> lockedClassHourList = convertor.convertToClassHourList(scheduleList, timeslotList);
            log.info("#ArrangeCourseServiceImpl.startScheduling#--数据库课表数据转换成排课课表数据完成，共{}条记录",
                    (lockedClassHourList != null ? lockedClassHourList.size() : 0));
            //将列表，按照timeslotCode，进行分组，即作为key，生成map
            ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> classHourMap = ClassHourUtil.getClassHourMap(lockedClassHourList);

            //获取单双拆班分组信息
            List<SubClassGroup> subGroupList = arrangeCourseDataSource.getSubGroupList(taskId, collegeId);

            log.info("#ArrangeCourseServiceImpl.startScheduling#--开始校区排课");
            //开启校区排课
            classHourMap = new SchoolScheduling().start(taskId,//排课选课计划id
                    teachingClassList, //教学班排课单元信息
                    roomList, //教室信息；
                    timeslotList, //排课课时信息
                    roomProhibitList,//禁排的教室列表信息；
                    classHourMap, //锁定的排课单元信息
                    teacherRuleList,//教师规则列表信息
                    courseRuleList,//课程规则列表信息；
                    courseLimitRuleList,//课程规则列表信息；
                    baseRule,//是否跨校区排课标识
                    weekNum, //学期总周数
                    collegeId,
                    subGroupList
            );
            log.info("ArrangeCourseServiceImpl.startScheduling--校区排课结束");
//            StopWatch stopWatch = new StopWatch();
//            stopWatch.start("计算冲突数");
//            int clashes = clashesProcess.calcClashes(classHourMap);
//            stopWatch.stop();
//            log.info("计算冲突数：" + clashes + "，耗时："+ stopWatch.getLastTaskTimeMillis());

            return classHourMap;
        }

        return null;
    }

    private void updateRoomType(List<ArrangeTeachingClassDto> teachingClassList, List<ArrangeRoomDto> roomList) {
        if (CollUtil.isNotEmpty(teachingClassList) && CollUtil.isNotEmpty(roomList)){
            Map<Long, Integer> roomTypeMap = roomList.stream().collect(Collectors.toMap(ArrangeRoomDto::getRoomId, ArrangeRoomDto::getRoomType));
            teachingClassList.forEach(o -> {
                if (o.getRoomId() != null){
                    Integer type = roomTypeMap.getOrDefault(o.getRoomId(), null);
                    if (type != null){
                        o.setRoomType(type);
                    }
                }
            });
        }
    }

    /**
     * 根据collegeId筛选map中的ClassHour对象
     *
     * @param classHourMap 排课结束后的课表数据存储的map
     * @param collegeId    院系id，空字符串代表教务管理员排课，null代表自动调整
     * @return
     */
    private ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> filterClassHourMap(ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> classHourMap,
                                                                                          String collegeId) {
        if (classHourMap != null && !classHourMap.isEmpty()) {
            ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> retMap = new ConcurrentHashMap<>();
            //遍历map的每个value，
            for (Map.Entry<String, CopyOnWriteArrayList<ClassHour>> entry : classHourMap.entrySet()) {
                //对应课时的，课表对象列表
                CopyOnWriteArrayList<ClassHour> classHourList = entry.getValue();
                //获取对应的key，即课时
                String timeslot = entry.getKey();
                //定义迭代器，进行列表数据的遍历
                Iterator iterator = classHourList.iterator();
                while (iterator.hasNext()) {
                    //获取当前遍历的课表对象
                    ClassHour classHour = (ClassHour) iterator.next();
                    //如果是当前处理的院系的课表数据
                    if (classHour.getCourseUnit() != null
                            && classHour.getCourseUnit().getCollegeId().equals(collegeId)) {
                        //如果课时存在
                        if (retMap.containsKey(timeslot)) {
                            //获取课时对应的课时列表数据信息
                            CopyOnWriteArrayList<ClassHour> list = retMap.get(timeslot);
                            //直接添加数据到列表
                            list.add(classHour);
                        } else {
                            //创建新的列表对象
                            CopyOnWriteArrayList<ClassHour> newList = new CopyOnWriteArrayList<>();
                            //存入当前的课时列表数据
                            newList.add(classHour);
                            //将数据存入map
                            retMap.put(timeslot, newList);
                        }
                    }
                }
            }
            return retMap;
        }

        //如果为空，直接返回
        return classHourMap;
    }

    /**
     * 将排课的数据，进行冲突检测、教学班排课状态标记，最后同步写入数据库；
     *
     * @param taskId       计划id
     * @param classHourMap 排课课表数据map
     * @param collegeId    院系id，教务管理员登录传null
     */
    private void syncData2DB(Integer taskId,
                             ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> classHourMap,
                             String collegeId, Integer majorProp) {
        if (classHourMap != null && !classHourMap.isEmpty()) {
            if (collegeId != null && majorProp != null) {
//                //筛选当前院系的课程
//                classHourMap = classHourMap.entrySet().parallelStream()
//                        .filter(entry -> entry.getValue().stream().anyMatch(classHour -> classHour instanceof ClassHour &&
//                                classHour.getCourseUnit().getCollegeId().equals(collegeId)))
//                        .collect(ConcurrentHashMap::new,
//                                (map, entry) -> map.put(entry.getKey(), entry.getValue()),
//                                ConcurrentHashMap::putAll);

                classHourMap = filterClassHourMap(classHourMap, collegeId);
            }

            //将排课数据，转换为数据库实体类对象列表
            //通过taskId，过滤掉了不是当前排课计划的课表单元数据
            List<Schedule> resultScheduleList = convertor.convertToScheduleList(classHourMap);
            log.info("ArrangeCourseServiceImpl.syncData2DB--排课课表转换成数据库课表数据完成，共生成{}条记录",
                    (resultScheduleList != null ? resultScheduleList.size() : 0));
            //将排课结果，记录到数据库表中
            arrangeCourseDataSource.addBathSchedule(taskId, resultScheduleList, collegeId, majorProp);
            log.info("ArrangeCourseServiceImpl.syncData2DB--课表数据写入数据库成功");

            //将排课冲突信息，写入数据库进行记录
            List<ScheduleConflictInfo> conflictList = recordClashes(taskId, classHourMap);
            log.info("ArrangeCourseServiceImpl.syncData2DB--校区排课完成");
            //更新教学班的排课状态信息，先处理未排的，然后处理已排（无冲突），最后处理已排（冲突）
            updateTeachingClassScheduleState(taskId, classHourMap, conflictList);
        }
    }

    /**
     * 记录冲突，将冲突写入数据库
     *
     * @param taskId       排课选课计划id
     * @param classHourMap 排完课的，课程课时map信息
     */
    private List<ScheduleConflictInfo> recordClashes(Integer taskId,
                                                     ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> classHourMap) {
        //定义存储冲突记录的列表
        List<ScheduleConflictInfo> conflictList = new ArrayList<>();

        //获取存在冲突的排课单元信息
        CopyOnWriteArrayList<ClassHour> clashesTimeslotRoomList = classHourMap.get("ClashesTimeslotRoom");
        if (clashesTimeslotRoomList != null && !clashesTimeslotRoomList.isEmpty()) {
            log.info("#ArrangeCourseServiceImpl.recordClashes#--存在冲突的教学班排课记录，共{}条",
                    (clashesTimeslotRoomList != null ? clashesTimeslotRoomList.size() : 0));
            //map的key为排课单元id，即CourseUnitId
            Map<Integer, List<ScheduleConflictInfo>> conflictMap = new HashMap<>();
            List<Long> roomIds = arrangeCourseDataSource.getCurrentRoom(taskId);
            //将存在冲突的排课单元，进行冲突记录
            conflictMap = clashesProcess.recordTimeslotRoomClashes(classHourMap,
                    clashesTimeslotRoomList, conflictMap, roomIds);
            log.info("#ArrangeCourseServiceImpl.recordClashes#--冲突检测完成，冲突记录已生成");
            //如果map中存在数据；
            if (!conflictMap.isEmpty()) {
                //将冲突记录的map，转换成list
                conflictList = conflictMap.entrySet().stream()
                        .flatMap(entry -> entry.getValue().stream())
                        .collect(Collectors.toList());
                log.info("#ArrangeCourseServiceImpl.recordClashes#--生成冲突记录，共{}条",
                        (conflictList != null ? conflictList.size() : 0));

            }
        }

        //写入数据库冲突表
        arrangeCourseDataSource.addBatchScheduleConflict(taskId, conflictList);
        log.info("#ArrangeCourseServiceImpl.recordClashes#--排课冲突记录写入数据库完成，共{}条记录",
                (conflictList != null ? conflictList.size() : 0));

        return conflictList;
    }

    /**
     * 更新教学班的排课状态信息，先处理未排的，然后处理已排（无冲突），最后处理已排（冲突）
     *
     * @param classHourMap 排课课表信息列表
     * @param conflictList 冲突信息列表
     */
    private void updateTeachingClassScheduleState(Integer taskId, ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> classHourMap,
                                                  List<ScheduleConflictInfo> conflictList) {
        //更新无冲突课程的，教学班的排课状态信息，为1，已排（无冲突）；
        updateNoclashScheduleState(taskId, classHourMap);
        log.info("ArrangeCourseServiceImpl.updateTeachingClassScheduleState--更新无冲突的教学班的排课状态为：已排（无冲突）--完成");
        log.info("#ArrangeCourseServiceImpl.updateTeachingClassScheduleState#--排课冲突的教学班排课课表记录，共{}条",
                (conflictList != null ? conflictList.size() : 0));

        //获取未指定教室课时分组信息的，排课单元信息
        CopyOnWriteArrayList<ClassHour> noTimeslotRoomList = classHourMap.get("NoTimeslotRoom");
        if (noTimeslotRoomList != null && noTimeslotRoomList.size() > 0) {
//           将未指定教室课时分组信息，作为冲突记录，进行记录
//            clashesRecordList = clashesProcess.recordNoTimeslotRoomClashes(noTimeslotRoomList, clashesRecordList);
            log.info("#ArrangeCourseServiceImpl.updateTeachingClassScheduleState#--未分配教室课时的教学班排课课表记录，共{}条",
                    (noTimeslotRoomList != null ? noTimeslotRoomList.size() : 0));
            //更新未分配教室的教学班的，排课状态信息为3：待排
            updateStateByClassHourList(noTimeslotRoomList, ScheduleState.UNARRANGE.getCode());
            log.info("ArrangeCourseServiceImpl.updateTeachingClassScheduleState--更新未分配教室课时的教学班的排课状态为：待排--完成");
        }
        //更新存在冲突的教室的教学班的，排课状态信息为2：已排（冲突）
        //这个要放在最后更新，因为正常排课的课程，在分配冲突教室之后，还会产生新的冲突；
        //所以这个放在更新正常的教学班的排课状态之后，可以对之前的更新（updateNoclashScheduleState），进行覆盖
        updateStateByConflictList(conflictList, ScheduleState.CONFLICT.getCode());
        log.info("ArrangeCourseServiceImpl.updateTeachingClassScheduleState--更新排课冲突的教学班的排课状态为：已排（冲突）--完成");
    }

    /**
     * 根据课表信息列表，更新教学班的排课状态
     *
     * @param classHourList 课表信息列表
     * @param scheduleState 更新状态，1已排（正常）、2已排（冲突）、3待排
     */
    private void updateStateByClassHourList(CopyOnWriteArrayList<ClassHour> classHourList,
                                            Integer scheduleState) {
        if (classHourList != null && !classHourList.isEmpty()) {
            //提取列表中的教学班id，并去重，生成列表
            List<CourseUnit> collect = classHourList.stream()
                    .map(classHour -> classHour.getCourseUnit())
                    .collect(Collectors.toList());

            //更新教学班排课状态
            updateScheduleState(scheduleState, collect);
        }
    }

    /**
     * 根据冲突信息列表，更新教学班的排课状态
     *
     * @param conflictList  冲突信息列表
     * @param scheduleState 更新状态，1已排（正常）、2已排（冲突）、3待排
     */
    private void updateStateByConflictList(List<ScheduleConflictInfo> conflictList,
                                           Integer scheduleState) {
        if (conflictList != null && !conflictList.isEmpty()) {
            //提取列表中的教学班id，并去重，生成列表
//            List<Long> teachingClassIdList = conflictList.stream()
//                    .map(conflict -> conflict.getTeachingClassId())
//                    .distinct()
//                    .collect(Collectors.toList());

            //更新教学班排课状态
//            updateSchedualState(teachingClassIdList, scheduleState);
            updateSchedualStateByType(conflictList, scheduleState);
        }
    }

    private void updateSchedualStateByType(List<ScheduleConflictInfo> conflictList, Integer scheduleState) {
        //提取列表中的教学班id，并去重，生成列表
        List<Long> teachingClassIdList = conflictList.stream()
                .map(conflict -> conflict.getTeachingClassId())
                .distinct()
                .collect(Collectors.toList());
        List<TeachingClassWeek> weeks = teachingClassWeekService.lambdaQuery()
                .in(TeachingClassWeek::getTeachingClassId, teachingClassIdList)
                .list();


        List<TeachingClassWeek> batch = new ArrayList<>();

        for (ScheduleConflictInfo conflictInfo : conflictList) {

            List<TeachingClassWeek> update = weeks.stream().filter(o -> o.getTeachingClassId().equals(conflictInfo.getTeachingClassId())
                            && o.getHourType().equals(conflictInfo.getHourType()))
                    .collect(Collectors.toList());
//            update.forEach(o -> o.setScheduleState(scheduleState));
            update.get(0).setScheduleState(scheduleState);
            batch.addAll(update);

        }
        teachingClassWeekService.updateBatchById(batch);
    }

    /**
     * 更新无冲突的课程，教学班的排课冲突状态信息；
     *
     * @param classHourMap 课表map，以timeslotCode作为key，即0101代表，周一第一节
     */
    private void updateNoclashScheduleState(Integer taskId, ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> classHourMap) {
        if (classHourMap != null && !classHourMap.isEmpty()) {
            List<ClassHour> noClashList = new ArrayList<>();
            //取出无冲突课程的课表列表
            for (Map.Entry<String, CopyOnWriteArrayList<ClassHour>> entry : classHourMap.entrySet()) {
                //获取map的key
                String key = entry.getKey();
                //获取正常无冲突的课程课表
                if (!key.equals("NoTimeslotRoom")
                        && !key.equals("ClashesTimeslotRoom")) {
                    //将正常的列表信息，加入新的列表
                    noClashList.addAll(entry.getValue());
                }
            }
            log.info("#ArrangeCourseServiceImpl.updateNoclashScheduleState#--无冲突的排课记录，共{}条",
                    (noClashList != null ? noClashList.size() : 0));
            if (noClashList != null && !noClashList.isEmpty()) {
                //提取列表中的教学班id，并去重，生成列表
                List<Long> teachingClassIdList = noClashList.stream()
                        .map(classHour -> classHour.getCourseUnit().getTeachingClassId())
                        .distinct()
                        .collect(Collectors.toList());
                log.info("#ArrangeCourseServiceImpl.updateNoclashScheduleState#--无冲突的排课记录对应的教学班，共{}个",
                        (teachingClassIdList != null ? teachingClassIdList.size() : 0));
                List<CourseUnit> courseUnitList = noClashList.stream()
                        .map(ClassHour::getCourseUnit)
                        .distinct()
                        .filter(o -> o.getTaskId().equals(taskId))
                        .collect(Collectors.toList());
                //过滤锁定的非正常的
                List<TeachingClassWeek> week = teachingClassWeekMapper.getUnNormal(taskId);
                if (CollUtil.isNotEmpty(week)) {
                    Map<Long, List<TeachingClassWeek>> map = week.stream().collect(Collectors.groupingBy(TeachingClassWeek::getTeachingClassId));
                    Set<Long> keys = map.keySet();
                    courseUnitList = courseUnitList.stream().filter(o -> {
                        Long teachingClassId = o.getTeachingClassId();
                        if (!keys.contains(teachingClassId)) {
                            return true;
                        }
                        List<TeachingClassWeek> teachingClassWeeks = map.get(teachingClassId);
                        List<Integer> types = teachingClassWeeks.stream().map(TeachingClassWeek::getHourType).collect(Collectors.toList());
                        if (types.contains(o.getTeachingType())) {
                            return false;
                        }
                        return true;
                    }).collect(Collectors.toList());
                }
                //将教学班排课状态设为，1已排（正常）
                updateScheduleState(ScheduleState.NORMAL.getCode(), courseUnitList);
            }
        }

    }

    /**
     * 更新指定教学班的排课冲突状态信息
     */
    private void updateScheduleState(int code, List<CourseUnit> courseUnitList) {
        if (CollUtil.isNotEmpty(courseUnitList)) {
//            teachingClassWeekMapper.updateScheduleStateByCourseUnit(code, courseUnitList);
            Consumer<List<CourseUnit>> studentConsumer = o -> teachingClassWeekMapper.updateScheduleStateByCourseUnit(code, o);
            BatchInsert.batchSplitInsert(courseUnitList, studentConsumer);
        }
    }

    /**
     * 针对排课手动调整功能，获取可用的教室、课时分组信息
     *
     * @param taskId        排课计划id
     * @param weeks         当前手动调整的教学班，需要调整的周次信息(二进制字符串，如：00011000000)
     * @param timeCodes     教学班所学的课时编码，多个以逗号分隔，如：0101、1012，0303、0304（null获取全部）
     * @param roomId        教学班排课所需的教室id（null获取全部）；
     * @param teachingClass 手动调课的教学班信息
     * @return
     */
    @Override
    @Deprecated
    public LinkedList<TimeslotRoom> getAvailableTimeslotRoomList(String schoolId,
                                                                 String termId,
                                                                 Integer taskId,
                                                                 String weeks,
                                                                 String timeCodes,
                                                                 Integer campusId,
                                                                 Integer buildingId,
                                                                 Long roomId,
                                                                 String keyword,
                                                                 ArrangeTeachingClassDto teachingClass,
                                                                 Integer departId,
                                                                 Integer conflictCheck, String collegeId, int outer) {


        //获取教室禁排数据
        List<ArrangeRoomRuleDto> roomProhibitList = arrangeCourseDataSource.getRoomRuleList(taskId, schoolId, termId, null, null);
        //获取教师排课规则
        List<ArrangeTeacherRuleDto> teacherRuleList = arrangeCourseDataSource.getTeacherRuleList(taskId, schoolId, termId, null);
        if (teacherRuleList != null
                && !teacherRuleList.isEmpty()) {
            //选出教师禁排规则
            teacherRuleList = teacherRuleList.stream()
                    .filter(teacherRule -> teacherRule.getFlag().equals(1))
                    .collect(Collectors.toList());
        }
        //获取课程禁排数据
        List<ArrangeCourseRuleDto> courseProhibitList = arrangeCourseDataSource.getCourseRuleList(taskId, null);
        //获取排课教室数据
        List<ArrangeRoomDto> roomList = arrangeCourseDataSource.getRoomList(taskId, schoolId, termId, null);
        //获取排课课时数据；
//        List<ArrangePeriod> timeslotList = arrangeCourseDataSource.getTimeslotList(taskId, schoolId, termId, null);
        List<ArrangePeriod> timeslotList = arrangeCourseDataSource.getTimeslotListV2(taskId, schoolId, termId, null);
        //获取本学期所有计划的课表信息
        List<ArrangeScheduleDto> lockedScheduleList = arrangeCourseDataSource.getLockedScheduleList(
                taskId, null, null, null, null, null);

        //将获取的锁定的课表，转换成ClassHour排课课时对象
        CopyOnWriteArrayList<ClassHour> lockedClassHourList = convertor.convertToClassHourList(lockedScheduleList, timeslotList);
        //将列表，按照timeslotCode，进行分组，即作为key，生成map
        ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> classHourMap = ClassHourUtil.getClassHourMap(lockedClassHourList);
        //获取学期的周次信息
        WeekDateVo weekInfo = arrangeCourseDataSource.getTermWeeks(taskId);
        //获取学期总周数，默认16周
        Long weekNum = 16L;
        if (weekInfo != null) {
            //获取学期总周数
            weekNum = weekInfo.getWeekCount();
        }
        //合并教室和课时信息
        LinkedList<TimeslotRoom> timeslotRoomList = new GenerateTimeslotRoom().getResult(roomList,
                timeslotList, roomProhibitList, classHourMap, weekNum);

        WeekDateVo dateVo = taskInfoService.countWeek(taskId);
        StringBuilder str = new StringBuilder();
        for (long i = 0; i < dateVo.getWeekCount(); i++) {
            str.append("0");
        }
        String removeWeek = str.toString();

        //如果是获取指定教学班，能用的空闲教室
        if (teachingClass != null) {
            //获取教学班所需的教师类型
            Integer filterRoomType = teachingClass.getRoomType();
            //获取教学班id
            Long teachingClassId = teachingClass.getTeachingClassId();
            //教学班容量
            Integer studentNum = teachingClass.getStudentNumber();
            //教学班排课所需的周次
            String classWeeks = teachingClass.getWeek();

            //选出指定教学班的禁排规则
            courseProhibitList = courseProhibitList.stream()
                    .filter(courseRule -> courseRule.getTeachingClassId().equals(teachingClassId)
                            && courseRule.getFlag() == 1
                    ).collect(Collectors.toList());
            teacherRuleList = teacherRuleList.stream().filter(o -> o.getFlag() == 1).collect(Collectors.toList());
            //将禁排的教师和课程，在对应的教学班上面做好标记；
            teachingClass = new TeacherAndCourseProhibitProcess().getResult(teachingClass,
                    courseProhibitList, teacherRuleList);

            //为了避免产生教师冲突  把教师的已排课时去掉(将已排课时放进禁排里面)
            removeWeek = removeTeacherScheduledTimeCodes(taskId, schoolId, termId, teachingClass, timeCodes, removeWeek);

            //为了避免产生学生冲突  把学生的已排课时去掉(将已排课时放进禁排里面)
            removeWeek = removeStudentScheduledTimeCodes(teachingClass, timeCodes, removeWeek);

            //找出周次符合当前教学班要求的课时信息
            timeslotRoomList = filterTimeslotRoomByWeeks(timeslotRoomList, weeks, conflictCheck, outer);

            //选出符合教室类型条件的教室
            String teachingClassCampusId = teachingClass.getCampusId();
            if (StrUtil.isNotEmpty(teachingClassCampusId)) {
                timeslotRoomList = timeslotRoomList.stream()
                        .filter(timeslotRoom -> timeslotRoom.getCampusId().equals(teachingClassCampusId))
                        .collect(Collectors.toCollection(LinkedList::new));

            }

            int preSize = timeslotRoomList.size();

//            if (filterRoomType != null){
//                timeslotRoomList = timeslotRoomList.stream()
//                        .filter(timeslotRoom -> timeslotRoom.getRoomType().equals(filterRoomType))
//                        .collect(Collectors.toCollection(LinkedList::new));
//
//            }
            if (timeslotRoomList.size() == 0 && departId == 0) {
                throw new BizException(999, "教学班所需类型的教室已全部被占用");
            }

            if (roomId != null) {
                timeslotRoomList = timeslotRoomList.stream()
                        .filter(timeslotRoom -> timeslotRoom.getRoomId().equals(roomId))
                        .collect(Collectors.toCollection(LinkedList::new));

            }
            if (timeslotRoomList.size() == 0 && departId == 0) {
//                Room room = roomService.getById(roomId);
//                String roomName = room == null ? "" : room.getRoomName();
                throw new BizException(999, "教学班所需的教室该课时已全部被占用");
            }


            //过滤禁排的课时
            timeslotRoomList = removePhrohibitRuleTimeslotRoom(teachingClass, timeslotRoomList);

            if (timeslotRoomList.size() == 0 && departId == 0) {
//                Room room = roomService.getById(roomId);
//                String roomName = room == null ? "" : "(" + room.getRoomName() + ")";
                throw new BizException(999, "教学班所需类型的教室课时已全部被占用");
            }

        }

        if (timeslotRoomList != null && !timeslotRoomList.isEmpty()) {
            //筛选对应的周次以及课时编码的数据
            timeslotRoomList = timeslotRoomList.stream()
                    .filter(timeslotRoom -> StrUtil.isBlank(weeks) || weeks.equals(BinaryUtil.binaryAnd(timeslotRoom.getWeeks(), weeks)))
                    .filter(timeslotRoom -> campusId == null || timeslotRoom.getCampusId().equals(String.valueOf(campusId)))
                    .filter(timeslotRoom -> buildingId == null || timeslotRoom.getBuildingId().equals(buildingId))
                    .filter(timeslotRoom -> roomId == null || timeslotRoom.getRoomId().equals(roomId))
                    .filter(timeslotRoom -> StrUtil.isBlank(timeCodes) || timeCodes.contains(timeslotRoom.getTimeslotCode()))
                    .filter(timeslotRoom -> StrUtil.isBlank(keyword) || timeslotRoom.getRoomName().contains(keyword) || timeslotRoom.getBuildingName().contains(keyword))
                    .collect(Collectors.toCollection(LinkedList::new));
        }

        if (timeslotRoomList.size() == 0 && departId == 0) {
            throw new BizException(999, "筛选的教室和课时已被占用");
        }

        return timeslotRoomList;
    }

    @Override
    public LinkedList<TimeslotRoom> getAvailableTimeslotRoomListV2(String schoolId,
                                                                   String termId,
                                                                   Integer taskId,
                                                                   String weeks,
                                                                   String timeCodes,
                                                                   Integer campusId,
                                                                   Integer buildingId,
                                                                   Integer selectRoomType,
                                                                   Long roomId,
                                                                   String keyword,
                                                                   ArrangeTeachingClassDto teachingClass,
                                                                   Integer departId,
                                                                   Integer conflictCheck, String collegeId,
                                                                   int outer) {


        //获取教室禁排数据
        List<ArrangeRoomRuleDto> roomProhibitList = arrangeCourseDataSource.getRoomRuleList(taskId, schoolId, termId, null, null);
        //获取教师排课规则
        List<ArrangeTeacherRuleDto> teacherRuleList = arrangeCourseDataSource.getTeacherRuleList(taskId, schoolId, termId, null);
        if (teacherRuleList != null
                && !teacherRuleList.isEmpty()) {
            //选出教师禁排规则
            teacherRuleList = teacherRuleList.stream()
                    .filter(teacherRule -> teacherRule.getFlag().equals(1))
                    .collect(Collectors.toList());
        }
        //获取课程禁排数据
        List<ArrangeCourseRuleDto> courseProhibitList = arrangeCourseDataSource.getCourseRuleList(taskId, null);
        //获取排课教室数据
        List<ArrangeRoomDto> roomList = arrangeCourseDataSource.getRoomList(taskId, schoolId, termId, null);
        //获取排课课时数据；
//        List<ArrangePeriod> timeslotList = arrangeCourseDataSource.getTimeslotList(taskId, schoolId, termId, null);
        List<ArrangePeriod> timeslotList = arrangeCourseDataSource.getTimeslotListV2(taskId, schoolId, termId, null);
        //获取本学期所有计划的课表信息
        List<ArrangeScheduleDto> lockedScheduleList = arrangeCourseDataSource.getLockedScheduleList(
                taskId, null, null, null, null, null);

        //将获取的锁定的课表，转换成ClassHour排课课时对象
        CopyOnWriteArrayList<ClassHour> lockedClassHourList = convertor.convertToClassHourList(lockedScheduleList, timeslotList);
        //将列表，按照timeslotCode，进行分组，即作为key，生成map
        ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> classHourMap = ClassHourUtil.getClassHourMap(lockedClassHourList);
        //获取学期的周次信息
        WeekDateVo weekInfo = arrangeCourseDataSource.getTermWeeks(taskId);
        //获取学期总周数，默认16周
        Long weekNum = 16L;
        if (weekInfo != null) {
            //获取学期总周数
            weekNum = weekInfo.getWeekCount();
        }
        //合并教室和课时信息
        LinkedList<TimeslotRoom> timeslotRoomList = new GenerateTimeslotRoom().getResult(roomList,
                timeslotList, roomProhibitList, classHourMap, weekNum);

        WeekDateVo dateVo = taskInfoService.countWeek(taskId);
        StringBuilder str = new StringBuilder();
        for (long i = 0; i < dateVo.getWeekCount(); i++) {
            str.append("0");
        }
        String removeWeek = str.toString();

        //如果是获取指定教学班，能用的空闲教室
        if (teachingClass != null) {
            //获取教学班所需的教师类型
            Integer filterRoomType = teachingClass.getRoomType();
            //获取教学班id
            Long teachingClassId = teachingClass.getTeachingClassId();
            //教学班容量
            Integer studentNum = teachingClass.getStudentNumber();
            //教学班排课所需的周次
            String classWeeks = teachingClass.getWeek();

            //找出周次符合当前教学班要求的课时信息
            timeslotRoomList = filterTimeslotRoomByWeeks(timeslotRoomList, weeks, conflictCheck, outer);

            //选出符合教室类型条件的教室
            String teachingClassCampusId = teachingClass.getCampusId();
            if (StrUtil.isNotEmpty(teachingClassCampusId)) {
                timeslotRoomList = timeslotRoomList.stream()
                        .filter(timeslotRoom -> timeslotRoom.getCampusId().equals(teachingClassCampusId))
                        .collect(Collectors.toCollection(LinkedList::new));

            }

            int preSize = timeslotRoomList.size();

//            if (filterRoomType != null){
//                timeslotRoomList = timeslotRoomList.stream()
//                        .filter(timeslotRoom -> timeslotRoom.getRoomType().equals(filterRoomType))
//                        .collect(Collectors.toCollection(LinkedList::new));
//
//            }
            if (timeslotRoomList.size() == 0 && departId == 0) {
                throw new BizException(999, "教学班所需类型的教室已全部被占用");
            }
            //前端已经不传
            if (roomId != null) {
                timeslotRoomList = timeslotRoomList.stream()
                        .filter(timeslotRoom -> timeslotRoom.getRoomId().equals(roomId))
                        .collect(Collectors.toCollection(LinkedList::new));

            }
            if (timeslotRoomList.size() == 0 && departId == 0) {
//                Room room = roomService.getById(roomId);
//                String roomName = room == null ? "" : room.getRoomName();
                throw new BizException(999, "教学班所需的教室该课时已全部被占用");
            }


            //选出指定教学班的禁排规则
            courseProhibitList = courseProhibitList.stream()
                    .filter(courseRule -> courseRule.getTeachingClassId().equals(teachingClassId)
                            && courseRule.getFlag() == 1
                    ).collect(Collectors.toList());
            //将禁排的教师和课程，在对应的教学班上面做好标记；
            teachingClass = new TeacherAndCourseProhibitProcess().getResult(teachingClass,
                    courseProhibitList, null);
            timeslotRoomList = removePhrohibitRuleTimeslotRoom(teachingClass, timeslotRoomList);
            if (timeslotRoomList.size() == 0 && departId == 0) {
                throw new BizException(999, "课程教学班将该课时设置为禁排");
            }

            teacherRuleList = teacherRuleList.stream().filter(o -> o.getFlag() == 1).collect(Collectors.toList());
            //将禁排的教师和课程，在对应的教学班上面做好标记；
            teachingClass = new TeacherAndCourseProhibitProcess().getResult(teachingClass,
                    null, teacherRuleList);
            timeslotRoomList = removePhrohibitRuleTimeslotRoom(teachingClass, timeslotRoomList);
            if (timeslotRoomList.size() == 0 && departId == 0) {
                throw new BizException(999, "教学班老师将该课时设置为禁排");
            }

            //为了避免产生教师冲突  把教师的已排课时去掉(将已排课时放进禁排里面)
            removeWeek = removeTeacherScheduledTimeCodes(taskId, schoolId, termId, teachingClass, timeCodes, removeWeek);
            timeslotRoomList = removePhrohibitRuleTimeslotRoom(teachingClass, timeslotRoomList);
            if (timeslotRoomList.size() == 0 && departId == 0) {
                throw new BizException(999, "教学班老师在该课时已经被安排其他课程");
            }

            //处理老师一天8节课问题
            timeslotRoomList = teacherOneDayMaxSection(taskId, teachingClass, timeslotRoomList);
            if (timeslotRoomList.size() == 0 && departId == 0) {
                throw new BizException(999, "老师一天已排满最大课时");
            }


            //为了避免产生学生冲突  把学生的已排课时去掉(将已排课时放进禁排里面)
            removeWeek = removeStudentScheduledTimeCodes(teachingClass, timeCodes, removeWeek);
            timeslotRoomList = removePhrohibitRuleTimeslotRoom(teachingClass, timeslotRoomList);
            if (timeslotRoomList.size() == 0 && departId == 0) {
                throw new BizException(999, "教学班的学生在该课时已经被安排其他课程");
            }


        }

        if (timeslotRoomList != null && !timeslotRoomList.isEmpty()) {
            if (outer == 1 && removeWeek.contains("1")) {
                for (TimeslotRoom timeslotRoom : timeslotRoomList) {
                    String roomWeek = timeslotRoom.getWeeks();
                    String useWeek = BinaryUtil.binaryXOR(roomWeek, removeWeek);
                    useWeek = BinaryUtil.binaryAnd(roomWeek, useWeek);
                    timeslotRoom.setWeeks(useWeek);
                }
            }
            //筛选对应的周次以及课时编码的数据
            timeslotRoomList = timeslotRoomList.stream()
//                    .filter(timeslotRoom -> StrUtil.isBlank(weeks)||weeks.equals(BinaryUtil.binaryAnd(timeslotRoom.getWeeks(), weeks)))
                    .filter(timeslotRoom -> StrUtil.isBlank(weeks) || outer == 0 ?
                            weeks.equals(BinaryUtil.binaryAnd(timeslotRoom.getWeeks(), weeks))
                            : BinaryUtil.binaryAnd(timeslotRoom.getWeeks(), weeks).contains("1"))
                    .filter(timeslotRoom -> campusId == null || timeslotRoom.getCampusId().equals(String.valueOf(campusId)))
                    .filter(timeslotRoom -> buildingId == null || timeslotRoom.getBuildingId().equals(buildingId))
                    .filter(timeslotRoom -> selectRoomType == null || timeslotRoom.getRoomType().equals(selectRoomType))
                    .filter(timeslotRoom -> roomId == null || timeslotRoom.getRoomId().equals(roomId))
                    .filter(timeslotRoom -> StrUtil.isBlank(timeCodes) || timeCodes.contains(timeslotRoom.getTimeslotCode()))
                    .filter(timeslotRoom -> StrUtil.isBlank(keyword) || timeslotRoom.getRoomName().contains(keyword) || timeslotRoom.getBuildingName().contains(keyword))
                    .collect(Collectors.toCollection(LinkedList::new));
        }

        if (timeslotRoomList.size() == 0 && departId == 0) {
            throw new BizException(999, "筛选的教室和课时已被占用");
        }
        timeslotRoomList.sort(Comparator.comparing(TimeslotRoom::getWeekSize).reversed());
        return timeslotRoomList;
    }

    private LinkedList<TimeslotRoom> teacherOneDayMaxSection(Integer taskId,
                                                             ArrangeTeachingClassDto teachingClass,
                                                             LinkedList<TimeslotRoom> timeslotRoomList) {
        if (CollUtil.isNotEmpty(teachingClass.getFixTimeslotCodes()) && CollUtil.isNotEmpty(timeslotRoomList)) {
            Integer maxSection = ruleUsableService.lambdaQuery().eq(RuleUsable::getTaskId, taskId)
                    .eq(RuleUsable::getCode, 5)
                    .one().getOptionType();
            if (maxSection != null && maxSection != 0) {
                List<String> teacherTimes = teachingClass.getFixTimeslotCodes();
                Map<String, List<String>> timeMap = new HashMap<>();
                for (String teacherTime : teacherTimes) {
                    String dayCode = teacherTime.substring(0, 2);
                    if (timeMap.containsKey(dayCode)) {
                        timeMap.get(dayCode).add(teacherTime);
                    } else {
                        List<String> time = new ArrayList<>();
                        time.add(teacherTime);
                        timeMap.put(dayCode, time);
                    }
                }

                for (Map.Entry<String, List<String>> entry : timeMap.entrySet()) {
                    Integer connectSection = teachingClass.getConnectSection();
                    if (entry.getValue().size() + connectSection > maxSection) {
                        String dayNo = entry.getKey().substring(0, 2);
                        timeslotRoomList = timeslotRoomList.stream()
                                .filter(o -> !o.getDayNo().equals(dayNo))
                                .collect(Collectors.toCollection(LinkedList::new));
                    }
                }
            }
            teachingClass.setFixTimeslotCodes(new ArrayList<>());
        }
        return timeslotRoomList;
    }

    @Override
    public LinkedList<TimeslotRoom> getAvailableTimeslotRoomListSelect(String schoolId,
                                                                       String termId,
                                                                       Integer taskId,
                                                                       String weeks,
                                                                       String timeCodes,
                                                                       Integer campusId,
                                                                       Integer buildingId,
                                                                       Long roomId,
                                                                       String keyword,
                                                                       ArrangeTeachingClassDto teachingClass,
                                                                       Integer departId,
                                                                       Integer conflictCheck, String collegeId) {

        if (StrUtil.isEmpty(teachingClass.getTcId())) {
            throw new BizException("教学班id为空");
        }

        //获取教室禁排数据
        List<ArrangeRoomRuleDto> roomProhibitList = arrangeCourseDataSource.getRoomRuleList(taskId, schoolId, termId, null, null);
        //获取教师排课规则
        List<ArrangeTeacherRuleDto> teacherRuleList = arrangeCourseDataSource.getTeacherRuleList(taskId, schoolId, termId, null);
        if (teacherRuleList != null
                && !teacherRuleList.isEmpty()) {
            //选出教师禁排规则
            teacherRuleList = teacherRuleList.stream()
                    .filter(teacherRule -> teacherRule.getFlag().equals(1))
                    .collect(Collectors.toList());
        }
        //获取排课教室数据
        List<ArrangeRoomDto> roomList = arrangeCourseDataSource.getRoomList(taskId, schoolId, termId, null);
        //获取排课课时数据；
//        List<ArrangePeriod> timeslotList = arrangeCourseDataSource.getTimeslotList(taskId, schoolId, termId, null);
        List<ArrangePeriod> timeslotList = arrangeCourseDataSource.getTimeslotListV2(taskId, schoolId, termId, null);
        //获取本学期所有计划的课表信息
        List<ArrangeScheduleDto> lockedScheduleList = arrangeCourseDataSource.getLockedScheduleList(
                taskId, null, null, null, null, null);

        if (CollUtil.isNotEmpty(teachingClass.getTeachingClassList())) {
            List<ArrangeScheduleDto> tempScheduleList = scheduleSelectService.getSchedules(taskId,
                    teachingClass.getTeachingClassList());
            lockedScheduleList.addAll(tempScheduleList);
        }

        //将获取的锁定的课表，转换成ClassHour排课课时对象
        CopyOnWriteArrayList<ClassHour> lockedClassHourList = convertor.convertToClassHourList(lockedScheduleList, timeslotList);
        //将列表，按照timeslotCode，进行分组，即作为key，生成map
        ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> classHourMap = ClassHourUtil.getClassHourMap(lockedClassHourList);
        //获取学期的周次信息
        WeekDateVo weekInfo = arrangeCourseDataSource.getTermWeeks(taskId);
        //获取学期总周数，默认16周
        Long weekNum = 16L;
        if (weekInfo != null) {
            //获取学期总周数
            weekNum = weekInfo.getWeekCount();
        }
        //合并教室和课时信息
        LinkedList<TimeslotRoom> timeslotRoomList = new GenerateTimeslotRoom().getResult(roomList,
                timeslotList, roomProhibitList, classHourMap, weekNum);
        //如果是获取指定教学班，能用的空闲教室
        if (teachingClass != null) {
            //获取教学班所需的教师类型
            Integer filterRoomType = teachingClass.getRoomType();
            //教学班容量
            Integer studentNum = teachingClass.getStudentNumber();
            //教学班排课所需的周次
            String classWeeks = teachingClass.getWeek();


            teacherRuleList = teacherRuleList.stream().filter(o -> o.getFlag() == 1).collect(Collectors.toList());
            //将禁排的教师和课程，在对应的教学班上面做好标记；
            teachingClass = new TeacherAndCourseProhibitProcess().getResult(teachingClass,
                    null, teacherRuleList);

            //为了避免产生教师冲突  把教师的已排课时去掉(将已排课时放进禁排里面)
            teachingClass = removeTeacherScheduledSelectTimeCodes(taskId, schoolId, termId, teachingClass);

            //为了避免产生学生冲突  把学生的已排课时去掉(将已排课时放进禁排里面)
            teachingClass = removeStudentScheduledSelectTimeCodes(taskId, teachingClass);

            //找出周次符合当前教学班要求的课时信息
            timeslotRoomList = filterTimeslotRoomByWeeks(timeslotRoomList, weeks, conflictCheck, 0);

            //选出符合教室类型条件的教室
            String teachingClassCampusId = teachingClass.getCampusId();
            if (StrUtil.isNotEmpty(teachingClassCampusId)) {
                timeslotRoomList = timeslotRoomList.stream()
                        .filter(timeslotRoom -> timeslotRoom.getCampusId().equals(teachingClassCampusId))
                        .collect(Collectors.toCollection(LinkedList::new));

            }

            int preSize = timeslotRoomList.size();

//            if (filterRoomType != null){
//                timeslotRoomList = timeslotRoomList.stream()
//                        .filter(timeslotRoom -> timeslotRoom.getRoomType().equals(filterRoomType))
//                        .collect(Collectors.toCollection(LinkedList::new));
//
//            }
            if (timeslotRoomList.size() == 0 && departId == 0) {
                throw new BizException(999, "教学班所需类型的教室已全部被占用");
            }

            if (roomId != null) {
                timeslotRoomList = timeslotRoomList.stream()
                        .filter(timeslotRoom -> timeslotRoom.getRoomId().equals(roomId))
                        .collect(Collectors.toCollection(LinkedList::new));

            }
            if (timeslotRoomList.size() == 0 && departId == 0) {
//                Room room = roomService.getById(roomId);
//                String roomName = room == null ? "" : room.getRoomName();
                throw new BizException(999, "教学班所需的教室该课时已全部被占用");
            }


            //过滤禁排的课时
            timeslotRoomList = removePhrohibitRuleTimeslotRoom(teachingClass, timeslotRoomList);

            if (timeslotRoomList.size() == 0 && departId == 0) {
//                Room room = roomService.getById(roomId);
//                String roomName = room == null ? "" : "(" + room.getRoomName() + ")";
                throw new BizException(999, "教学班所需类型的教室课时已全部被占用");
            }

        }

        if (timeslotRoomList != null && !timeslotRoomList.isEmpty()) {
            //筛选对应的周次以及课时编码的数据
            timeslotRoomList = timeslotRoomList.stream()
                    .filter(timeslotRoom -> StrUtil.isBlank(weeks) || weeks.equals(BinaryUtil.binaryAnd(timeslotRoom.getWeeks(), weeks)))
                    .filter(timeslotRoom -> campusId == null || timeslotRoom.getCampusId().equals(String.valueOf(campusId)))
                    .filter(timeslotRoom -> buildingId == null || timeslotRoom.getBuildingId().equals(buildingId))
                    .filter(timeslotRoom -> roomId == null || timeslotRoom.getRoomId().equals(roomId))
                    .filter(timeslotRoom -> StrUtil.isBlank(timeCodes) || timeCodes.contains(timeslotRoom.getTimeslotCode()))
                    .filter(timeslotRoom -> StrUtil.isBlank(keyword) || timeslotRoom.getRoomName().contains(keyword) || timeslotRoom.getBuildingName().contains(keyword))
                    .collect(Collectors.toCollection(LinkedList::new));
        }

        if (timeslotRoomList.size() == 0 && departId == 0) {
            throw new BizException(999, "筛选的教室和课时已被占用");
        }

        return timeslotRoomList;
    }

    /**
     * @param taskId:
     * @param teachingClass:
     * @Description: 选课模块
     * @Author: liufeng
     * @Date: 2024/8/22 022 13:56
     * @return:
     */
    private ArrangeTeachingClassDto removeStudentScheduledSelectTimeCodes(Integer taskId, ArrangeTeachingClassDto teachingClass) {
        if (CollUtil.isNotEmpty(teachingClass.getStudentIdList())) {
            List<Long> tcIds = teachingClassMapper.getTeachingClassIds(taskId);
            List<TeachingClassStudent> teachingClassStudents = teachingClassStudentMapper.selectList(
                    new LambdaQueryWrapper<TeachingClassStudent>()
                            .in(TeachingClassStudent::getTeachingClassId, tcIds)
                            .in(TeachingClassStudent::getStudentId, teachingClass.getStudentIdList()));
            tcIds = teachingClassStudents.stream().map(TeachingClassStudent::getTeachingClassId).distinct().collect(Collectors.toList());
            HashSet<String> times = new HashSet<>();
            List<ViewSchedule> scheduleList = scheduleMapper.getScheduledSelectTimeCodes(taskId, tcIds);
            if (CollUtil.isNotEmpty(scheduleList)) {
                for (ViewSchedule schedule : scheduleList) {
                    String week = teachingClass.getWeek();
                    String scheduleWeek = schedule.getWeek();
                    if (BinaryUtil.binaryAnd(week, scheduleWeek).contains("1")) {
                        times.add(schedule.getTimeCode());
                    }
                }
            }
            List<String> tempTimeCode = scheduleSelectService.lambdaQuery()
                    .eq(ScheduleSelect::getTeachingClassId, teachingClass.getTcId())
                    .isNotNull(ScheduleSelect::getTimeCode).list()
                    .stream().map(ScheduleSelect::getTimeCode).distinct().collect(Collectors.toList());
            times.addAll(tempTimeCode);
            teachingClass.setProhibitTimeslotCodes(dealTimeslotCodes(teachingClass.getProhibitTimeslotCodes(),
                    new ArrayList<>(times)));
        }
        return teachingClass;
    }

    private String removeStudentScheduledTimeCodes(ArrangeTeachingClassDto teachingClass,
                                                   String timeCodes,
                                                   String removeWeek) {
        if (teachingClass.getTeachingClassId() != null) {
//            List<String> times = teachingClassStudentMapper.getScheduledTimeCodes(teachingClass.getTeachingClassId());
            List<ViewSchedule> schedules = teachingClassStudentMapper.getScheduledTimeCodesWeek(teachingClass.getTeachingClassId());

//            List<ViewSchedule> schedules = teachingClassStudentMapper.getScheduledTimeCodes(teachingClass.getTeachingClassId());
//            //第一次 第二次排课的问题  会把所有课表全删除
//            schedules = schedules.stream()
//                    .filter(schedule ->
//                            !schedule.getTeachingClassId().equals(teachingClass.getTeachingClassId())
//                                    || !schedule.getHourType().equals(teachingClass.getHourType())
//                                    || !StrUtil.isNotEmpty(schedule.getTimeCode())
//                                    || !schedule.getWeek().equals(teachingClass.getWeek())
//                    ).collect(Collectors.toList());
//            List<String> times = schedules.stream().map(ViewSchedule::getTimeCode).distinct().collect(Collectors.toList());

            HashSet<String> times = new HashSet<>();
            if (CollUtil.isNotEmpty(schedules)) {
                if (StrUtil.isNotEmpty(timeCodes)) {
                    List<String> codesList = Arrays.stream(timeCodes.split(",")).collect(Collectors.toList());
                    schedules = schedules.stream().filter(o -> codesList.contains(o.getTimeCode())).collect(Collectors.toList());
                }
                Map<String, List<ViewSchedule>> scheduleMap = schedules.stream().collect(Collectors.groupingBy(ViewSchedule::getTimeCode));
                for (Map.Entry<String, List<ViewSchedule>> entry : scheduleMap.entrySet()) {
                    List<String> weeks = entry.getValue().stream().map(ViewSchedule::getWeek).collect(Collectors.toList());
                    String scheduleWeek = BinaryUtil.binaryORMore(weeks);
                    removeWeek = BinaryUtil.binaryOR(removeWeek, scheduleWeek);
                    String week = teachingClass.getWeek();
                    if (BinaryUtil.binaryAnd(week, scheduleWeek).equals(week)) {
                        times.add(entry.getKey());
                    }


//                for (ViewSchedule schedule : schedules) {
//                    String week = teachingClass.getWeek();
//                    String scheduleWeek = schedule.getWeek();
////                    if (BinaryUtil.binaryAnd(week,scheduleWeek).contains("1")) {
//                    if (BinaryUtil.binaryAnd(week,scheduleWeek).equals(week)) {
//                        times.add(schedule.getTimeCode());
//                    }
                }

//                List<String> collect = times.stream().sorted().collect(Collectors.toList());
                log.info("学生已排：{},{}", times.toString(), times);
                teachingClass.setProhibitTimeslotCodes(dealTimeslotCodes(teachingClass.getProhibitTimeslotCodes(),
                        new ArrayList<>(times)));
            }
        }
        return removeWeek;
    }

    private String removeTeacherScheduledTimeCodes(Integer taskId, String schoolId,
                                                   String termId,
                                                   ArrangeTeachingClassDto teachingClass,
                                                   String timeCodes,
                                                   String removeWeek) {
        if (StrUtil.isNotEmpty(teachingClass.getTeacherIds())) {
            List<Integer> taskIds = taskInfoService.lambdaQuery().eq(TaskInfo::getSchoolId, schoolId)
                    .eq(TaskInfo::getTerm, termId).list()
                    .stream().map(TaskInfo::getTaskId).collect(Collectors.toList());
            HashSet<String> times = new HashSet<>();
            String[] teacherIdArr = teachingClass.getTeacherIds().split(",");
            for (String splitTeacherId : teacherIdArr) {
                List<ViewSchedule> schedules = scheduleMapper.getTeacherScheduledTimeCodes(taskIds, splitTeacherId);

                if (CollUtil.isNotEmpty(schedules)) {
                    if (StrUtil.isNotEmpty(timeCodes)) {
                        List<String> codesList = Arrays.stream(timeCodes.split(",")).collect(Collectors.toList());
                        schedules = schedules.stream().filter(o -> codesList.contains(o.getTimeCode())).collect(Collectors.toList());
                    }
                    Map<String, List<ViewSchedule>> scheduleMap = schedules.stream().collect(Collectors.groupingBy(ViewSchedule::getTimeCode));
                    for (Map.Entry<String, List<ViewSchedule>> entry : scheduleMap.entrySet()) {
                        List<String> weeks = entry.getValue().stream().map(ViewSchedule::getWeek).collect(Collectors.toList());
                        String scheduleWeek = BinaryUtil.binaryORMore(weeks);
                        removeWeek = BinaryUtil.binaryOR(removeWeek, scheduleWeek);
                        String week = teachingClass.getWeek();
                        if (BinaryUtil.binaryAnd(week, scheduleWeek).equals(week)) {
                            times.add(entry.getKey());
                        }
                    }


//                    for (ViewSchedule schedule : schedules) {
//                        String week = teachingClass.getWeek();
//                        String scheduleWeek = schedule.getWeek();
////                        if (BinaryUtil.binaryAnd(week,scheduleWeek).contains("1")) {
//                        if (BinaryUtil.binaryAnd(week,scheduleWeek).equals(week)) {
//                            times.add(schedule.getTimeCode());
//                        }
//                    }
                    log.info("教师已排：{},{}", times.toString(), times);
                }
            }
//            List<String> collect = times.stream().sorted().collect(Collectors.toList());
            teachingClass.setProhibitTimeslotCodes(dealTimeslotCodes(teachingClass.getProhibitTimeslotCodes(),
                    new ArrayList<>(times)));
            if (CollUtil.isNotEmpty(times)) {
                teachingClass.setFixTimeslotCodes(new ArrayList<>(times));
            }
        }
        return removeWeek;
    }

    /**
     * @param taskId:
     * @param schoolId:
     * @param termId:
     * @param teachingClass:
     * @Description: 选课模块
     * @Author: liufeng
     * @Date: 2024/8/22 022 13:56
     * @return:
     */
    private ArrangeTeachingClassDto removeTeacherScheduledSelectTimeCodes(Integer taskId, String schoolId, String termId, ArrangeTeachingClassDto teachingClass) {
        if (StrUtil.isNotEmpty(teachingClass.getTeacherIds())) {
            List<Integer> taskIds = taskInfoService.lambdaQuery().eq(TaskInfo::getSchoolId, schoolId)
                    .eq(TaskInfo::getTerm, termId).list()
                    .stream().map(TaskInfo::getTaskId).collect(Collectors.toList());
            HashSet<String> times = new HashSet<>();
            String[] teacherIdArr = teachingClass.getTeacherIds().split(",");
            for (String splitTeacherId : teacherIdArr) {
//                List<ViewSchedule> schedules = scheduleMapper.getTeacherScheduledTimeCodes(taskIds, splitTeacherId);
//
//                if (CollUtil.isNotEmpty(schedules)) {
//                    times.addAll(schedules.stream().map(ViewSchedule::getTimeCode).collect(Collectors.toList()));
//                }
                List<ViewSchedule> schedules = scheduleMapper.getTeacherScheduledTimeCodes(taskIds, splitTeacherId);

                if (CollUtil.isNotEmpty(schedules)) {
                    for (ViewSchedule schedule : schedules) {
                        String week = teachingClass.getWeek();
                        String scheduleWeek = schedule.getWeek();
                        if (BinaryUtil.binaryAnd(week, scheduleWeek).contains("1")) {
                            times.add(schedule.getTimeCode());
                        }
                    }
                }
            }

            List<InnerTeachingClass> teachingClassList = teachingClass.getTeachingClassList().stream()
                    .filter(o -> Arrays.stream(o.getTeacherIds().split(","))
                            .allMatch(t -> isTeacherIdExist(teachingClass.getTeacherIds(), t)))
                    .collect(Collectors.toList());
            if (CollUtil.isNotEmpty(teachingClassList)) {
                List<ArrangeScheduleDto> selectSchedules = scheduleSelectService.getSchedules(taskId, teachingClassList)
                        .stream().filter(o -> StrUtil.isNotEmpty(o.getTimeCode()))
                        .collect(Collectors.toList());
                if (CollUtil.isNotEmpty(selectSchedules)) {
                    for (ArrangeScheduleDto schedule : selectSchedules) {
                        String week = teachingClass.getWeek();
                        String scheduleWeek = schedule.getWeek();
                        if (BinaryUtil.binaryAnd(week, scheduleWeek).contains("1")) {
                            times.add(schedule.getTimeCode());
                        }
                    }
                }
            }

            teachingClass.setProhibitTimeslotCodes(dealTimeslotCodes(teachingClass.getProhibitTimeslotCodes(),
                    new ArrayList<>(times)));
        }
        return teachingClass;
    }

    protected boolean isTeacherIdExist(String teacherIds, String teacherId) {
        //如果teacherIds为空或者空字符串
        if (StrUtil.isBlank(teacherIds)) {
            //返回不包含
            return false;
        }
        //将字符串进行拆分
        String[] teacherIdArr = teacherIds.split(",");
        for (String splitTeacherId : teacherIdArr) {
            if (splitTeacherId.equals(teacherId)) {
                return true;
            }
        }
        return false;
    }

    private String dealTimeslotCodes(String prohibitTimeslotCodes, ArrayList<String> times) {
        if (prohibitTimeslotCodes == null) {
            prohibitTimeslotCodes = "";
        }
        for (String time : times) {
            if (!prohibitTimeslotCodes.contains(time)) {
                prohibitTimeslotCodes += time + ",";
            }
        }
        return prohibitTimeslotCodes;
    }

    /**
     * 根据教学班的周次，找出符合要求的教室课时分组信息；
     *
     * @param timeslotRoomList 教室课时分组信息列表
     * @param classWeeks       教学班排课所需的周次
     * @param conflictCheck
     * @return
     */
    private LinkedList<TimeslotRoom> filterTimeslotRoomByWeeks(LinkedList<TimeslotRoom> timeslotRoomList,
                                                               String classWeeks, Integer conflictCheck,
                                                               int outer) {
        if (timeslotRoomList != null && !timeslotRoomList.isEmpty()) {
            //定义迭代器
            Iterator iterator = timeslotRoomList.iterator();
            while (iterator.hasNext()) {
                TimeslotRoom timeslotRoom = (TimeslotRoom) iterator.next();
                //获取教室课时分组的周次
                String timeslotRoomWeeks = timeslotRoom.getWeeks();
                //将两个二进制字符串，进行与操作,比如10101和11111，进行与操作，结果是10101
                String result = BinaryUtil.binaryAnd(timeslotRoomWeeks, classWeeks);
                String conflict = BinaryUtil.binaryXOR(timeslotRoomWeeks, classWeeks);
                timeslotRoom.setClashWeeks(conflict);
                timeslotRoom.setWeekSize(WeekUtil.weekSize(result));
                if (outer == 0 ? !result.equals(classWeeks) : !result.contains("1")) {
                    //那么，需要将这个教室课时分组信息，从列表删除掉
                    iterator.remove();
                }

//                if (WeekUtil.weekSize(classWeeks) > WeekUtil.weekSize(timeslotRoomWeeks)) {
//                    //那么，需要将这个教室课时分组信息，从列表删除掉
//                    iterator.remove();
//                }

//                if (conflictCheck != null && conflictCheck == 0){
//                    //如果结果字符串和教学班的周次不相等，说明当前教室课时分组的周次，是不符合当前教学班的周次需求的
//                    if (!result.equals(classWeeks)) {
//                        //那么，需要将这个教室课时分组信息，从列表删除掉
//                        iterator.remove();
//                    }
//                }
            }
        }

        return timeslotRoomList;
    }

    /**
     * 移除指定教学班禁排的教室课时分组信息
     *
     * @param teachingClass    指定的教学班信息
     * @param timeslotRoomList 当前空闲的，所有的教室课时分组信息
     * @return
     */
    private LinkedList<TimeslotRoom> removePhrohibitRuleTimeslotRoom(ArrangeTeachingClassDto teachingClass,
                                                                     LinkedList<TimeslotRoom> timeslotRoomList) {
        if (teachingClass == null
                || timeslotRoomList == null
                || timeslotRoomList.isEmpty()) {
            log.info("ArrangeCourseServiceImpl--->> removeTeachingClassPhrohibitTimeslot---->>Excetption:data is null!!");
            return timeslotRoomList;
        }
        //定义列表遍历的迭代器
        Iterator iterator = timeslotRoomList.iterator();
        while (iterator.hasNext()) {
            TimeslotRoom timeslotRoom = (TimeslotRoom) iterator.next();
            if (teachingClass.getProhibitTimeslotCodes().contains(timeslotRoom.getTimeslotCode())) {
                iterator.remove();
            }
        }

        return timeslotRoomList;
    }

    /**
     * 手动调整之后的数据更新，更新冲突表和教学班的排课冲突状态
     *
     * @param schoolId        学校id
     * @param termId          学期id
     * @param taskId          计划id
     * @param campusId        校区id
     * @param teachingClassId 教学班Id
     */
    public void manualAdjustmentUpdate(String schoolId,
                                       String termId,
                                       Integer taskId,
                                       String campusId,
                                       Long teachingClassId) {
        //获取排课课时数据；
        List<ArrangePeriod> allTimeslotList = arrangeCourseDataSource.getTimeslotList(taskId, schoolId, termId, "");
        //锁定后的课表信息，为null，获取所有的课表数据
        List<ArrangeScheduleDto> scheduleList = arrangeCourseDataSource.getLockedScheduleList(taskId, campusId, null, null, null, null);
        //将获取的课表，转换成ClassHour排课课时对象
        CopyOnWriteArrayList<ClassHour> allClassHourList = convertor.convertToClassHourList(scheduleList, allTimeslotList);

        //从教学班中，筛选出当前教学班的课表信息；
        CopyOnWriteArrayList<ClassHour> teachingClassClassHourList = allClassHourList.stream()
                .filter(classHour -> classHour.getTimeslotRoom() != null)
                .filter(classHour -> classHour.getCourseUnit().getTeachingClassId().equals(teachingClassId))
                .collect(Collectors.toCollection(CopyOnWriteArrayList::new));
        //将列表，按照timeslotCode，进行分组，即作为key，生成map
        ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> classHourMap = ClassHourUtil.getClassHourMap(allClassHourList);

        //获取当前教学班的冲突数据,以及与这个教学班冲突的其他教学班的冲突数据
        List<ScheduleConflictInfo> teachingClassConflictList = arrangeCourseDataSource.getTeachingClassConflictList(teachingClassId);

        //map的key为排课单元id，即CourseUnitId
        Map<Integer, List<ScheduleConflictInfo>> conflictMap = new HashMap<>();
        List<Long> roomIds = arrangeCourseDataSource.getCurrentRoom(taskId);
        //将当前教学班的排课单元，进行冲突记录
        //其实就是获取调整后教学班产生的新的冲突记录
        conflictMap = clashesProcess.recordTimeslotRoomClashes(classHourMap,
                teachingClassClassHourList, conflictMap, roomIds);

        //如果map中存在数据；
        if (!conflictMap.isEmpty()) {
            //将冲突记录的map，转换成list
            List<ScheduleConflictInfo> conflictList = conflictMap.entrySet().stream()
                    .flatMap(entry -> entry.getValue().stream())
                    .collect(Collectors.toList());
            //处理与当前教学班冲突的教学班的，冲突信息以及排课状态信息
            dealWithClashesTeachingClassConflictInfo(teachingClassConflictList,
                    conflictList);

            //批量更新，不存在则添加，相应的冲突信息；
            arrangeCourseDataSource.updateAndAddConflictList(conflictList);
            //将相应教学班的排课状态，更新为已排(冲突)
            updateStateByConflictList(conflictList, ScheduleState.CONFLICT.getCode());

        } else {//没有冲突

            //如果之前存在冲突，则删除
            if (teachingClassConflictList != null && !teachingClassConflictList.isEmpty()) {
                arrangeCourseDataSource.removeConflictList(teachingClassConflictList);
                //跟新状态
                List<ScheduleConflictInfo> noConflictTeachingClass = teachingClassConflictList.stream()
                        .filter(o -> !Objects.equals(o.getTeachingClassId(), teachingClassId))
                        .collect(Collectors.toList());
                updateStateByTeachingClasss(noConflictTeachingClass, ScheduleState.NORMAL.getCode());

            }
            CopyOnWriteArrayList<ClassHour> normal = teachingClassClassHourList.stream()
                    .filter(o -> StrUtil.isNotEmpty(o.getTimeslotRoom().getTimeslotCode())
                            && o.getTimeslotRoom().getRoomId() != null).collect(Collectors.toCollection(CopyOnWriteArrayList::new));
            //将教学班的排课状态，更新为已排（无冲突）
            updateStateByClassHourList(normal, ScheduleState.NORMAL.getCode());
            //从教学班中，筛选出当前教学班的课表信息；
            CopyOnWriteArrayList<ClassHour> teachingClassClassNoHourList = allClassHourList.stream()
                    .filter(classHour -> classHour.getTimeslotRoom() == null)
                    .filter(classHour -> classHour.getCourseUnit().getTeachingClassId().equals(teachingClassId))
                    .collect(Collectors.toCollection(CopyOnWriteArrayList::new));
            //将教学班的排课状态，更新为待排
            updateStateByClassHourList(teachingClassClassNoHourList, ScheduleState.UNARRANGE.getCode());
        }
    }

    private void updateStateByTeachingClasss(List<ScheduleConflictInfo> noConflictTeachingClass, int code) {
        if (CollUtil.isNotEmpty(noConflictTeachingClass)) {
            teachingClassWeekMapper.updateScheduleStateByType(code, noConflictTeachingClass);
        }
    }

    /**
     * 处理与当前教学班冲突的教学班的，冲突信息以及排课状态信息
     * 即：调整
     *
     * @param teachingClassConflictList 调整前，当前教学班以及与当前教学班冲突的教学班，的冲突信息；
     * @param conflictList              调整后，当前教学班以及与当前教学班冲突的教学班，的冲突信息列表；
     */
    private void dealWithClashesTeachingClassConflictInfo(List<ScheduleConflictInfo> teachingClassConflictList,
                                                          List<ScheduleConflictInfo> conflictList) {
        //处理与当前教学班冲突的教学班的冲突更新情况
        if (teachingClassConflictList != null && !teachingClassConflictList.isEmpty()) {
            //将之前数据库记录的冲突信息全部删除掉
            arrangeCourseDataSource.removeConflictList(teachingClassConflictList);
            //定义迭代器
            Iterator iterator = teachingClassConflictList.iterator();
            //筛选调整前与当前教学班冲突，但是调整后与当前教学班不冲突了的，冲突信息
            while (iterator.hasNext()) {
                //获取冲突信息
                ScheduleConflictInfo conflict = (ScheduleConflictInfo) iterator.next();
                //如果新生成的冲突列表中，包括原来的冲突信息
                if (conflictList.contains(conflict)) {
                    //从原来的冲突信息中，删除掉
                    //这样原来的冲突信息中，剩下的就是，之前与当前教学班冲突的教学班的冲突信息了
                    iterator.remove();
                }
            }
            //如果之前存在冲突,调整之后，没出冲突了，这时需要对原来冲突的教学班进行标志，修改为已排(无冲突)
            updateStateByConflictList(teachingClassConflictList, ScheduleState.NORMAL.getCode());
        }
    }

}
